#pragma once

#include <boost/any.hpp>
#include <boost/utility.hpp>
#include <concepts>
#include <functional>
#include <memory>
#include <string>
#include <type_traits>
#include <unordered_map>

namespace UTILS {
using KEY_TYPE = uint32_t;
template <typename Base, typename Derived>
concept is_derived_from = std::is_base_of_v<Base, Derived>;

class AbstractFactory : boost::noncopyable {
public:
  enum class FactoryType : uint8_t {
    TCP_CLIENT_APP = 0,
    TCP_SERVER_APP = 1,
    NONE = 255,
  };

public:
  template <typename T, typename... Args> void Register(const KEY_TYPE strKey) {
    std::function<T *(Args...)> func = [](Args... args) {
      return new T(args...);
    };
    Register(strKey, func);
  }

  template <typename Base, typename Depend, typename... Args>
  typename std::enable_if<std::is_base_of<Base, Depend>::value>::type
  RegisterBase(const KEY_TYPE strKey) {
    std::function<Base *(Args...)> func = [](Args... args) {
      return new Depend(args...);
    };
    Register(strKey, func);
  }
  template <typename T, typename... Args> struct register_t {
    register_t(const FactoryType type, const KEY_TYPE strKey)
        : m_appId_(strKey), m_factoryType_(type) {
      std::function<T *(Args...)> func = [](Args... args) {
        return new T(args...);
      };
      UTILS::AbstractFactory::getInstance(type).Register(strKey, func);
    }
    ~register_t() {
      UTILS::AbstractFactory::getInstance(m_factoryType_).UnRegister(m_appId_);
    }

  private:
    const uint32_t m_appId_;
    const FactoryType m_factoryType_;
  };

  template <typename Base, typename Depend, typename... Args>
  struct baseRegister_t {
    baseRegister_t(const FactoryType type, const KEY_TYPE strKey)
        : m_appId_(strKey), m_factoryType_(type) {
      static_assert(is_derived_from<Base, Depend>,
                    "Depend must be derived from Base");
      std::function<Base *(Args...)> func = [](Args... args) {
        return new Depend(args...);
      };
      UTILS::AbstractFactory::getInstance(m_factoryType_)
          .Register(m_appId_, func);
    }
    ~baseRegister_t() {
      UTILS::AbstractFactory::getInstance(m_factoryType_).UnRegister(m_appId_);
    }

  private:
    const uint32_t m_appId_;
    const FactoryType m_factoryType_;
  };

  template <typename Base, typename Depend> struct baseRegisterNoParam_t {
    baseRegisterNoParam_t(const FactoryType type, const KEY_TYPE strKey)
        : m_appId_(strKey), m_factoryType_(type) {
      static_assert(is_derived_from<Base, Depend>,
                    "Depend must be derived from Base");
      std::function<Base *()> func = []() { return new Depend(); };
      UTILS::AbstractFactory::getInstance(m_factoryType_)
          .Register(m_appId_, func);
    }
    ~baseRegisterNoParam_t() {
      UTILS::AbstractFactory::getInstance(m_factoryType_).UnRegister(m_appId_);
    }

  private:
    const uint32_t m_appId_;
    const FactoryType m_factoryType_;
  };

  template <typename T, typename... Args>
  std::shared_ptr<T> getObject(const KEY_TYPE strKey, Args... args) {
    T *ptr = Resolve<T *, Args...>(strKey, std::forward<Args>(args)...);
    return std::shared_ptr<T>(ptr);
  }
  static AbstractFactory &getInstance(const FactoryType type) {
    switch (type) {
    case FactoryType::TCP_CLIENT_APP: {
      static AbstractFactory s_tcpClientAbstractFactory;
      return s_tcpClientAbstractFactory;
    } break;
    case FactoryType::TCP_SERVER_APP: {
      static AbstractFactory s_tcpServerAbstractFactory;
      return s_tcpServerAbstractFactory;
    } break;
    default: {
      throw std::invalid_argument(
          "AbstractFactory::getInstance set error paramater");
    } break;
    }
  }

  void UnRegister(const KEY_TYPE key) {
    if (m_creatorMap.count(key)) {
      m_creatorMap.erase(key);
    }
  }

private:
  void Register(const KEY_TYPE strKey, boost::any constructor) {
    if (m_creatorMap.count(strKey)) {
      throw std::invalid_argument("strKey is already register!!!");
    }
    m_creatorMap.emplace(strKey, constructor);
  }

  template <typename T, typename... Args>
  T Resolve(const KEY_TYPE strKey, Args... args) {
    if (!m_creatorMap.count(strKey)) {
      throw std::invalid_argument("strKey is NOT register!!!");
    }
    boost::any functionHandler = m_creatorMap[strKey];
    auto func = boost::any_cast<std::function<T(Args...)>>(functionHandler);
    return func(std::forward<Args>(args)...);
  }

private:
  std::unordered_map<KEY_TYPE, boost::any> m_creatorMap;
};

template <typename T>
concept has_static_init_deinit = requires(T) {
  T::init(); // 尝试调用静态成员函数
  T::deinit();
};
template <has_static_init_deinit T> void init(T &obj) { T::init(); }
template <has_static_init_deinit T> void deinit(T &obj) { T::init(); }
} // namespace UTILS
#define APPFactory(type) UTILS::AbstractFactory::getInstance(type)

#define REGISTER_MESSAGE_VNAME(T) reg_msg_##T##_

#define REGISTER_MESSAGE(T, type, key, ...)                                    \
  static AbstractFactory::register_t<T, __VA_ARGS__> REGISTER_MESSAGE_VNAME(   \
      T)(type, key);

#define BASE_REGISTER_MESSAGE(Base, Depend, type, key, ...)                    \
  static AbstractFactory::baseRegister_t<Base, Depend, __VA_ARGS__>            \
      REGISTER_MESSAGE_VNAME(Depend)(type, key);

#define BASE_REGISTER_MESSAGE_NO_PARAM(Base, Depend, type, key)                \
  static AbstractFactory::baseRegisterNoParam_t<Base, Depend>                  \
      REGISTER_MESSAGE_VNAME(Depend)(type, key);